/// 
/// MaDAson - Toolkit for Model Driven Software Development
/// 
/// Copyright [2006] Marcus Lankenau
/// 
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///  
///     http://www.apache.org/licenses/LICENSE-2.0
///  
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
/// 

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Core;
using NUnit.Framework;


namespace Madason.MetaModel.Transformation.Tests
{
	public class TestClassSubclass : Class
	{}

	public class TestAttributeSubclass : Madason.MetaModel.Attribute
	{ }

	public class TestAssociationSubclass : Madason.MetaModel.Association
	{ }

	public class TestOperationSubclass : Madason.MetaModel.Operation
	{ }

	public class TestNamespaceSubclass : Madason.MetaModel.Namespace
	{ }

	public class TestStateSubclass : Madason.MetaModel.State
	{
	}


	[TestFixture]
	public class TestTransformer
	{
		[Test]
		public void TestTransformClass()
		{
			// build namespace with class
			Namespace ns = new Namespace();
			Class cls = new Class();
			cls.Id = "someID";
			cls.Name = "MyClass";
			cls.StereotypeName = "entity";
			ns.Classes.Add(cls);

			Rule rule = new Rule();
			rule.Stereotype = "entity";
			rule.Scope = RuleScope.Class;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestClassSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(ns);

			Assert.AreEqual(1, ns.Classes.Count);
			Assert.IsInstanceOfType(typeof(TestClassSubclass), ns.Classes[0]);

			Assert.AreEqual(cls.Name, ns.Classes[0].Name);
			Assert.AreEqual(cls.Id, ns.Classes[0].Id);
		}

		/// <summary>
		/// Check wheather references back to the class e.g. from ops or attr oder assocs
		/// are correct after replacement
		/// </summary>
		[Test]
		public void TestTransformClassCheckBackRefs()
		{
			// build namespace with class
			Namespace ns = new Namespace();
			Class cls = new Class();
			cls.Id = "someID";
			cls.Name = "MyClass";
			cls.StereotypeName = "entity";
			ns.Classes.Add(cls);

			Attribute attr = new Attribute();
			attr.Class = cls;
			cls.Attributes.Add(attr);

			Operation op = new Operation();
			op.Class = cls;
			cls.Operations.Add(op);

			Association assoc = new Association();
			assoc.Class = cls;
			cls.Associations.Add(assoc);

			Rule rule = new Rule();
			rule.Stereotype = "entity";
			rule.Scope = RuleScope.Class;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestClassSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(ns);

			cls = ns.Classes[0];
			Assert.AreSame(cls, cls.Operations[0].Class);
			Assert.AreSame(cls, cls.Attributes[0].Class);
			Assert.AreSame(cls, cls.Associations[0].Class);

		}



		/// <summary>
		/// This test is for checking that all assocs to class beeing replaced are also replaced
		/// </summary>
		[Test]
		public void TestTransformClassCheckAssoc()
		{
			// build namespace with class
			Model ns = new Model();
			Class cls = new Class();
			cls.Id = "someID1";
			cls.Name = "MyClass";
			cls.StereotypeName = "entity";
			cls.Namespace = ns;
			ns.Classes.Add(cls);

			Class cls2 = new Class();
			cls2.Id = "someID2";
			cls2.Name = "MyClass";
			cls2.StereotypeName = "entity";
			cls2.Namespace = ns;
			ns.Classes.Add(cls2);

			Association assoc = new Association();
			assoc.Class = cls2;
			assoc.TargetClassId = cls.Id;
			cls2.Associations.Add(assoc);

			Rule rule = new Rule();
			rule.Stereotype = "entity";
			rule.Scope = RuleScope.Class;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestClassSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(ns);

			Assert.AreEqual(2, ns.Classes.Count);
			Assert.IsInstanceOfType(typeof(TestClassSubclass), ns.Classes[0]);

			Assert.IsInstanceOfType(typeof(TestClassSubclass), ns.Classes[1].Associations[0].TargetClass);
		}

		


		[Test]
		public void TestTransformAttribute()
		{
			// build namespace with class
			Namespace ns = new Namespace();
			Class cls = new Class();
			cls.Id = "someID";
			cls.Name = "MyClass";
			ns.Classes.Add(cls);

			Attribute attr = new Attribute();
			attr.Id = "someAttrID";
			attr.Name = "MyAttribute";
			attr.StereotypeName = "PrimaryKey";
			attr.Class = cls;
			cls.Attributes.Add(attr);

			Rule rule = new Rule();
			rule.Stereotype = "PrimaryKey";
			rule.Scope = RuleScope.Attribute;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestAttributeSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(ns);
			

			Assert.AreEqual(1, cls.Attributes.Count);
			Assert.IsInstanceOfType(typeof(TestAttributeSubclass), cls.Attributes[0]);

			Assert.AreEqual(attr.Name, cls.Attributes[0].Name);
			Assert.AreEqual(attr.Id, cls.Attributes[0].Id);
		}


		[Test]
		public void TestTransformAttributeByParentStereotype()
		{
			// build namespace with class
			Namespace ns = new Namespace();
			Class cls = new Class();
			cls.Id = "someID";
			cls.Name = "MyClass";
			cls.StereotypeName = "entity";
			ns.Classes.Add(cls);

			Attribute attr = new Attribute();
			attr.Id = "someAttrID";
			attr.Name = "MyAttribute";
			
			attr.Class = cls;
			cls.Attributes.Add(attr);

			Rule rule = new Rule();
			rule.ParentStereotype = "entity";
			rule.Scope = RuleScope.Attribute;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestAttributeSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(ns);


			Assert.AreEqual(1, cls.Attributes.Count);
			Assert.IsInstanceOfType(typeof(TestAttributeSubclass), cls.Attributes[0]);

			Assert.AreEqual(attr.Name, cls.Attributes[0].Name);
			Assert.AreEqual(attr.Id, cls.Attributes[0].Id);
		}


		[Test]
		public void TestTransformAssociationByParentStereotype()
		{
			// build namespace with class
			Namespace ns = new Namespace();
			Class cls = new Class();
			cls.Id = "someID";
			cls.Name = "MyClass";
			cls.StereotypeName = "entity";
			ns.Classes.Add(cls);

			Association assoc = new Association();
			assoc.Id = "someID";
			assoc.Name = "SomeAssociation";
			assoc.TargetClassId = cls.Id;
			assoc.Class = cls;
			cls.Associations.Add(assoc);

			Rule rule = new Rule();
			rule.ParentStereotype = "entity";
			rule.Scope = RuleScope.Association;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestAssociationSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(ns);


			Assert.AreEqual(1, cls.Associations.Count);
			Assert.IsInstanceOfType(typeof(TestAssociationSubclass), cls.Associations[0]);

			Assert.AreEqual(assoc.Name, cls.Associations[0].Name);
			Assert.AreEqual(assoc.Id, cls.Associations[0].Id);
		}




		[Test]
		public void TestTransformOperation()
		{
			// build namespace with class
			Namespace ns = new Namespace();
			Class cls = new Class();
			cls.Id = "someID";
			cls.Name = "MyClass";
			ns.Classes.Add(cls);

			Operation op = new Operation();
			op.Id = "someAttrID";
			op.Name = "MyAttribute";
			op.StereotypeName = "Finder";
			op.Class = cls;
			cls.Operations.Add(op);

			Rule rule = new Rule();
			rule.Stereotype = "Finder";
			rule.Scope = RuleScope.Operation;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestOperationSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(ns);


			Assert.AreEqual(1, cls.Operations.Count);
			Assert.IsInstanceOfType(typeof(TestOperationSubclass), cls.Operations[0]);

			Assert.AreEqual(op.Name, cls.Operations[0].Name);
			Assert.AreEqual(op.Id, cls.Operations[0].Id);
		}

		[Test]
		public void TestTransformNamespace()
		{
			Model model = new Model();

			// build namespace with class
			Namespace ns = new Namespace();
			ns.StereotypeName = "MavenMaster";
			Class cls = new Class();
			cls.Id = "someID";
			cls.Name = "MyClass";
			ns.Classes.Add(cls);
			model.Namespaces.Add(ns);

			Rule rule = new Rule();
			rule.Stereotype = "MavenMaster";
			rule.Scope = RuleScope.Namespace;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestNamespaceSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(model);
			Assert.AreEqual(1, model.Namespaces.Count);
			Assert.AreEqual("TestNamespaceSubclass", model.Namespaces[0].GetType().Name);
		}

		[Test]
		public void TestTransformState()
		{
			Model model = new Model();

			StateMachine sm = new StateMachine();
			model.Statemachines.Add(sm);

			State st = new State();
			st.StereotypeName = "StrutsAction";
			st.Name = "SomeStateName";
			sm.States.Add(st);
			st.Parent = sm;

			Rule rule = new Rule();
			rule.Stereotype = "StrutsAction";
			rule.Scope = RuleScope.State;
			rule.Target = "Madason.MetaModel.Transformation.Tests.TestStateSubclass";
			RuleList ruleList = new RuleList();
			ruleList.Add(rule);

			Transformer transformer = new Transformer(ruleList);
			transformer.Transform(model);
			Assert.AreEqual(1, model.Statemachines.Count);
			Assert.AreEqual(1, model.Statemachines[0].States.Count);
			Assert.AreEqual("TestStateSubclass", model.Statemachines[0].States[0].GetType().Name);
		}
	}
}
